#pragma once

#include<iostream>
#include<sys/types.h>//网络通信头文件
#include<sys/socket.h>
#include<cstdlib>
#include<cstring>
#include<unistd.h>
#include<netinet/in.h>
#include<arpa/inet.h>
#include<pthread.h>
#include"log.hpp"


#define PORT 8081
#define BACKLOG 5

class TcpServer
{
private:
    int port;//传入端口号，创建套接字对象，不需要ip，云服务器随机绑定ip就行
    int listen_sock;//套接字
    static TcpServer* svr;

private:
    TcpServer(int _port = PORT):port(_port),listen_sock(-1) {}

    TcpServer(const TcpServer &s){}
   

public:
    static TcpServer *getinstance(int port)
    {
        static pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;
        if(nullptr == svr)
        {
            pthread_mutex_lock(&lock);//满足条件上锁
            if(nullptr == svr)
            {
                svr = new TcpServer(port);
                svr->InitServer();
            }
            pthread_mutex_unlock(&lock);//解锁
        }
        return svr;
    }

    void InitServer()//初始化套接字
    {
        Socket();
        Bind();
        Listen();
        LOG(INFO, "Init socket ... success");
    }

    void Socket()//创建套接字
    {
        listen_sock = socket(AF_INET, SOCK_STREAM, 0);
        if(listen_sock < 0)//创建失败，直接退出
        {
            LOG(FATAL, "socket error!");
            exit(1);
        }
        int opt = 1;
        setsockopt(listen_sock, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));//设置套接字复用，请求服务难免有些服务无法使用，而套接字绑定后主动停止服务还会等待一段时间，所以要复用
        LOG(INFO, "create socket ... success");

    }

    int Sock()
    {
        return listen_sock;
    }


    void Bind()
    {
        struct sockaddr_in local;
        memset(&local, 0, sizeof(local));
        local.sin_family = AF_INET;
        local.sin_port = htons(port);//主机序列转换
        local.sin_addr.s_addr = INADDR_ANY;//云服务器不能直接绑定ip
        //inet_aton("101.43.8.154",&local.sin_addr);

        if(bind(listen_sock, (struct sockaddr*)&local, sizeof(local)) < 0)
        {
            //绑定失败
            LOG(FATAL, "bind error!");

            exit(2);
        }
        LOG(INFO, "bind sock ... success");
    }

    void Listen()
    {
        if(listen(listen_sock, BACKLOG) < 0) LOG(FATAL, "listen socket error!"), exit(3);
        LOG(INFO, "listen socket ... success");
    }

    
    // ~TcpServer() 
    // { 
    //     //close(listen_sock)
    // }

    ~TcpServer() 
    {
        if(listen_sock >= 0) close(listen_sock);
    }

};

TcpServer* TcpServer::svr = nullptr;